package net.lab1024.sa.admin.module.business.flow.service;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.constant.FlowConstants;
import net.lab1024.sa.admin.module.business.flow.dao.FlwDeModelDao;
import net.lab1024.sa.admin.module.business.flow.domain.entity.FlwDeModelEntity;
import net.lab1024.sa.admin.module.business.flow.domain.form.FlwDeModelAddForm;
import net.lab1024.sa.admin.module.business.flow.domain.form.FlwDeModelQueryForm;
import net.lab1024.sa.admin.module.business.flow.domain.form.FlwDeModelUpdateForm;
import net.lab1024.sa.admin.module.business.flow.domain.vo.FlwDeModelVO;
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee;
import net.lab1024.sa.admin.module.system.login.service.LoginService;
import net.lab1024.sa.admin.util.AdminRequestUtil;
import net.lab1024.sa.base.common.domain.RequestUser;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
import net.lab1024.sa.base.common.util.SmartPageUtil;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.domain.PageResult;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.lab1024.sa.base.common.util.SmartRequestUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.engine.RepositoryService;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

/**
 * 流程设计 Service
 *
 * @Author ADog
 * @Date 2025-10-06 20:16:41
 * @Copyright 1.0
 */

@Slf4j
@Service
public class FlwDeModelService extends FlowServiceFactory {

    @Resource
    private FlwDeModelDao flwDeModelDao;

    /**
     * 分页查询
     */
    public PageResult<FlwDeModelVO> queryPage(FlwDeModelQueryForm queryForm) {
        Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
        List<FlwDeModelVO> list = flwDeModelDao.queryPage(page, queryForm);
        return SmartPageUtil.convert2PageResult(page, list);
    }

    /**
     * 添加流程模型
     */
    @Transactional
    public ResponseDTO<String> add(FlwDeModelAddForm addForm) {
        FlwDeModelEntity flwDeModelEntity = SmartBeanUtil.copy(addForm, FlwDeModelEntity.class);

        // 获取当前登录用户
        RequestUser requestUser = SmartRequestUtil.getRequestUser();
        flwDeModelEntity.setCreatedBy(requestUser.getUserName());
        flwDeModelEntity.setLastUpdatedBy(requestUser.getUserName());

        // 获取当前的modelKey
        String modelKey = addForm.getModelKey();

        // 版本号管理 - 查找相同modelKey的最新版本
        FlwDeModelEntity entity = flwDeModelDao.selectByModelKey(modelKey);

        if (entity != null) {
            // 已存在，版本号+1并更新
            flwDeModelEntity.setVersion(entity.getVersion() + 1);
            flwDeModelDao.insert(flwDeModelEntity);
        } else {
            // 不存在该流程则创建
            flwDeModelEntity.setVersion(1);
            flwDeModelDao.insert(flwDeModelEntity);
        }

        return ResponseDTO.ok();
    }


    /**
     * 更新
     */
    public ResponseDTO<String> update(FlwDeModelUpdateForm updateForm) {
        FlwDeModelEntity flwDeModelEntity = SmartBeanUtil.copy(updateForm, FlwDeModelEntity.class);
        // 1、设置更新时间
        LocalDateTime LastUpdated = LocalDateTime.now();
        flwDeModelEntity.setLastUpdated(LastUpdated);
        // 2、设置更新人
        flwDeModelEntity.setLastUpdatedBy(SmartRequestUtil.getRequestUser().getUserName());
        flwDeModelDao.updateById(flwDeModelEntity);
        return ResponseDTO.ok();
    }

    /**
     * 批量删除
     */
    public ResponseDTO<String> batchDelete(List<Integer> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return ResponseDTO.ok();
        }

        flwDeModelDao.deleteBatchIds(idList);
        return ResponseDTO.ok();
    }

    /**
     * 单个删除
     */
    public ResponseDTO<String> delete(Integer id) {
        if (null == id) {
            return ResponseDTO.ok();
        }

        flwDeModelDao.deleteById(id);
        return ResponseDTO.ok();
    }


    /**
     * 部署流程（在你原有代码基础上简化修复）
     */
    public ResponseDTO<String> deployFlow(Integer id) {
        // 1、根据流程id获取流程定义信息（保留你原有的校验）
        FlwDeModelEntity flwDeModelEntity = flwDeModelDao.selectById(id);
        if (flwDeModelEntity == null || flwDeModelEntity.getModelXml() == null) {

        }

        try {
            // 2、处理 BPMN XML（只修复关键问题，保留你原有的替换逻辑）
            String modelXml = flwDeModelEntity.getModelXml();

            // 替换 Camunda 命名空间和前缀为 Flowable（原逻辑保留）
            // 修复：只有当不存在flowable命名空间时才添加
            if (!modelXml.contains("xmlns:flowable=\"http://flowable.org/bpmn\"")) {
                modelXml = modelXml.replaceAll("xmlns:camunda=\"http://camunda.org/schema/1.0/bpmn\"", "xmlns:flowable=\"http://flowable.org/bpmn\"");
            } else {
                // 如果已经有flowable命名空间，只需要替换前缀
                modelXml = modelXml.replaceAll("xmlns:camunda=\"http://camunda.org/schema/1.0/bpmn\"", "");
            }

            // 清理可能产生的多余空格
            modelXml = modelXml.replace("  ", " ").replace(" >", ">");

            modelXml = modelXml.replaceAll("targetNamespace=\"http://bpmn.io/bpmn\"", "targetNamespace=\"http://www.flowable.org/processdef\"");
            modelXml = modelXml.replaceAll("exporterVersion=\"5.1.2\"", "exporterVersion=\"6.7.2\"");
            modelXml = modelXml.replaceAll("camunda:", "flowable:");

            // 强制设置为可执行流程（原逻辑保留，补充：若没有isExecutable属性则添加）
            if (!modelXml.contains("isExecutable=")) {
                modelXml = modelXml.replaceFirst("<process ", "<process isExecutable=\"true\" ");
            } else {
                modelXml = modelXml.replaceAll("isExecutable=\"false\"", "isExecutable=\"true\"");
            }

            // 3、添加流程名称（修复原正则匹配不完整、未转义特殊字符的问题）
            String processName = flwDeModelEntity.getName();
            if (processName != null && !processName.trim().isEmpty() && !modelXml.contains("name=\"")) {
                // 修复1：正则匹配含任意属性的process标签，避免漏加
                // 修复2：转义XML特殊字符（如引号、&），避免解析报错
                String escapedName = escapeXml(processName.trim());
                modelXml = modelXml.replaceFirst(
                        "(<process\\s+[^>]*?id=\"[^\"]+\")",  // 匹配带id属性的process标签（无论是否有其他属性）
                        "$1 name=\"" + escapedName + "\""     // 在id后追加name属性
                );
            }

            // 4、执行部署（保留你原有的部署逻辑，仅调整文件名后缀适配Flowable）
            repositoryService.createDeployment()
                    .name(processName) // 部署名称
                    .key(flwDeModelEntity.getModelKey()) // 部署Key（重复部署自动升级版本）
                    // 修复：文件名后缀用.bpmn20.xml（Flowable推荐，避免识别异常）
                    .addString((processName == null ? "default" : processName) + ".bpmn20.xml", modelXml)
                    .disableSchemaValidation() // 保留你的原配置，快速跳过非核心校验
                    .deploy();

            return ResponseDTO.ok("流程部署成功");
        } catch (Exception e) {
            log.error("流程部署失败，模型ID: {}", id, e);
            return ResponseDTO.ok("流程部署失败");
        }
    }


    /**
     * 验证XML格式是否正确
     */
    private void validateXmlFormat(String xml) throws Exception {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            builder.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            log.error("XML格式验证失败，XML内容预览: {}", xml.substring(0, Math.min(200, xml.length())));
            throw new RuntimeException("XML格式错误: " + e.getMessage(), e);
        }
    }

    /**
     * 辅助方法：XML特殊字符转义（解决引号、&等导致的解析错误）
     */
    private String escapeXml(String value) {
        if (value == null) return "";
        // 转义所有可能导致XML解析错误的字符
        return value.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&apos;")
                .replace("\r", "&#13;")
                .replace("\n", "&#10;");
    }
}